package org.simple.framework.boot.config;

import org.simple.framework.web.result.base.SimpleResult;
import org.simple.framework.web.result.base.SimpleResultCode;
import org.simple.framework.web.result.exception.BaseSimpleException;
import org.simple.framework.web.result.exception.service.ForbiddenException;
import org.simple.framework.web.result.exception.web.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;

/**
 * 项目名称：simple-framework
 * 类名称：ExceptionsHandler
 * 类描述：统一异常处理
 * 创建时间：2018/7/17
 *
 * @author sisyphus   (E-mail:1620657419@qq.com)
 * @version v1.0
 */
@RestControllerAdvice
public class ExceptionsHandler {

    private static final Logger logger = LoggerFactory.getLogger(ExceptionsHandler.class);

    @Value(value = "${simple.framework.web.result.show-error:true}")
    private boolean isShowError = true;

    /**
     * 捕获自定义异常
     *
     * @param exception .
     * @return .
     */
    @ExceptionHandler(BaseSimpleException.class)
    public SimpleResult baseResultExceptionHandler(BaseSimpleException exception) {
        return toBaseResult(exception);
    }

    @ExceptionHandler(ParameterException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public SimpleResult exceptionHandler(ParameterException exception) {
        return toBaseResult(exception);
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public SimpleResult handle(MethodArgumentNotValidException exception) {
        HashMap<String, String> dataMap = new HashMap<>();
        SimpleResult simpleResult = toBaseResult(exception);
        simpleResult.setBaseCode(SimpleResultCode.BAD_REQUEST);
        simpleResult.setData(dataMap);

        exception.getBindingResult().getFieldErrors().forEach(fieldError -> {
            dataMap.put(fieldError.getField(), fieldError.getDefaultMessage());
        });
        return simpleResult;
    }

    @ExceptionHandler(UnauthorizedException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public SimpleResult exceptionHandler(UnauthorizedException exception) {
        return toBaseResult(exception);
    }

    @ExceptionHandler(ForbiddenException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public SimpleResult exceptionHandler(ForbiddenException exception) {
        return toBaseResult(exception);
    }

    @ExceptionHandler(AuthLockedException.class)
    @ResponseStatus(HttpStatus.LOCKED)
    public SimpleResult exceptionHandler(AuthLockedException exception) {
        return toBaseResult(exception);
    }

    @ExceptionHandler(ServerException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public SimpleResult exceptionHandler(ServerException exception) {
        return toBaseResult(exception);
    }

    @ExceptionHandler(NotImplementedException.class)
    @ResponseStatus(HttpStatus.NOT_IMPLEMENTED)
    public SimpleResult exceptionHandler(NotImplementedException exception) {
        return toBaseResult(exception);
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public SimpleResult exceptionHandler(Exception exception) {
        logger.error("", exception);
        return toBaseResult(exception);
    }

    private SimpleResult toBaseResult(Exception exception) {
        SimpleResult baseResult;
        if (exception instanceof BaseSimpleException) {
            baseResult = ((BaseSimpleException) exception).getBaseResult();
        } else {
            baseResult = new ServerException().getBaseResult();
        }
        if (isShowError) {
            baseResult.buildError(exception);
        }
        return baseResult;
    }

}
